Skip to content

TS-08 声明文件、模块解析

为什么需要声明文件

当引入了全局的库之后,比如jQuery库,会在ts文件中使用$符,在ts文件中直接使用是会提示找不到文件的,是因为没有声明文件;

声明文件的查找

可以在tsconfig.json文件中,添加include字段,配置声明文件的路径,如果不配置,则会查找所有文件夹下面的.d.ts文件;

json
{
    "include": [
        "./scr/**/*.ts", // 代表src下面某个文件夹下面的声明文件
        "./src/**/*.d.ts"
    ]
}

声明文件使用declare关键字来声明文件;

查看声明文件

ts中,大多数库都被社区编写了声明文件,在node_modules找到安装的库,之后查看*.d.ts文件,里面就是写好的声明文件,如果没有,则需要手动安装,安装时加上@types/*即可,如果安装成功了,说明有这个库的声明文件,如果找不到安装的模块,则需要手动编写声明文件;

全局库

如何判断是否是全局可以使用的变量:

官方声明文件的例子:官方模块,可以参考global.d.ts文件的例子;

通过定义document或者window上面添加方法时,都是全局可以使用的变量

ts
// 如果添加了一个全局的getTitle方法,并且返回的是string, 当声明了之后则可以使用了;
declare function getTitle(): string

当修改了声明文件时,需要重新编译,否则报错;

模块化库

使用import语句或者require语句的,一般都是模块化库

可以参数官方的module-*.d.ts的模板;

UMD库

UMD模块是指那些既可以作为模块使用(通过导入)又可以作为全局(在没有模块加载器的环境里)使用的模块。

识别UMD模块

js
(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define(["libName"], factory);
    } else if (typeof module === "object" && module.exports) {
        module.exports = factory(require("libName"));
    } else {
        root.returnExports = factory(root.libName);
    }
}(this, function (b) {

很多库都是UMD库,比如jquerymoment

修改全局模块编写声明文件

一个全局插件是全局代码,它们会改变全局对象的结构。 对于 全局修改的模块,在运行时存在冲突的可能。

当我们在StringArray等原型上面添加了方法时,如何填写声明文件

ts
String.prototype.getFirstLetter = function(){
    return this[0]
}

// global.d.ts 写声明文件
// 利用声明合并
interface String {
    getFirstLetter(): string
}

使用依赖

依赖全局库

如果库依赖了某个全局库,使用reference指定types来引入该模块

ts
/// <reference types='moment'/>

依赖模块

使用import语句

ts
import * as moment from "moment";

依赖UMD库

  • 如果你的全局库依赖于某个UMD模块,使用/// <reference types指令:

    ts
    /// <reference types="moment" />
    
    function getThing(): moment;
  • 如果你的模块或UMD库依赖于一个UMD库,使用import语句:

    ts
    import * as someLib from 'someLib';

    不要使用///reference引入

注意:

  1. 防止命名冲突,因为都是在全局填写的,很容易产生冲突,建议将相关的东西放在命名空间里面,使用对象的形式去访问,防止命名污染
  2. 一些插件添加或修改已存在的顶层模块的导出部分。 当然这在CommonJS和其它加载器里是允许的,ES模块被当作是不可改变的因此这种模式就不可行了。 因为TypeScript是能不预知加载器类型的,所以没没在编译时保证,但是开发者如果要转到ES6模块加载器上应该注意这一点。

快捷外部模块声明

如果使用一个新模块,不想花时间精力为该模块填写声明,只需要在typing文件夹下面创建文件夹编写即可,比如moment

ts
// typings/moment/index.d.ts
declare module 'moment' //快速导出模块

模块解析

以下内容进行了解就可以了

模块解析分为两种:node解析和classic解析,通过tsconfig.json文件的moduleResolution设置,如果不设置默认为classic解析方式;

classic解析策略:

  • 当省略ts文件时首先会查看.ts文件,如果找不到则查找.d.ts文件,还是找不到则向上一级去查找,继续按照前面两种文件类型查找;

node解析策略:

  • 模拟nodejs模板解析策略,在编译阶段定位模块文件的,首先找.ts文件,之后找.tsx文件,之后找.d.ts三种文件;

nodejs会查找package.json里面的main确定入口文件,而ts会首先查找types确定入口文件,之后再查找main入口文件

模块解析配置项

通过配置项,来确定模块的导入,配置项在tsconfig.json文件

  • baseUrl:用来设置编译之后文件都放在哪个文件夹下;

  • paths: 用来设置路径映射,paths是相对于baseUrl的,指定paths就必须指定baseUrl,常用于配置第三方模块的引入,经常在node_modules/@typessrc/typings文件夹查找,设置:

    json
    {
        "baseUrl": "./", // 如果是当前根目录,就填写一个.即可
        "paths": {
            "*": ["node_modules/@types", "src/typings"]
        }
    }
  • rootDirs:路径列表,在编译时,编译器会将这个路径列表中的内容放到一个文件夹中,当modules文件夹中的index.ts要引入ts-modules文件夹里面的a.ts文件,设置了路径列表之后,只需要写相对路径即可

    ts
    {
        "rootDirs": ["src/modules", "src/ts-modules"]
    }

Released under the MIT License.